//////////////////////////////////////////////////////////////////
// MattiseOS Kernel
// Date: 2008
// Author: Matthew Iselin
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// at your option) any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
//////////////////////////////////////////////////////////////////

// Includes
#include <mattise.h>
#include <stdint.h>
#include <stdarg.h>
#include <mem/util.h>
#include <mem/heap.h>
#include <core/pit.h>
#include <kernio/io.h>
#include <process/common.h>

// Variables

// rather than having a process table, i'm trying something new
struct pentry* p_readyq = 0; // ready queue
struct pentry* p_alreadyq = 0; // swapped with ready when ready becomes empty
struct pentry* p_deadq = 0; // dead queue (for removal)
struct pentry* p_waitq = 0; // waiting queue - will need to write some extra code
struct pentry* p_sleepq = 0; // sleep queue (advantage is that if no processes are sleeping IRQ0 is faster)

// the process table
struct pentry* ptable = 0;

// the current process (a copy of the actual pointer)
struct context* currprocess;

// the last used PID
uint32_t lastpid = 0;

// Functions

// gets the current thread id
uint32_t getpid()
{
	// grab the pid from the current process pointer
	return currprocess->id;
}

// sets up multitasking
void kInitTasking()
{
    // allocate space for the process table (on the kernel heap)
    ptable = (struct pentry*) malloc( sizeof( struct pentry ) );

    // set it up
    ptable->prev = 0;
    ptable->me = 0;
    ptable->next = 0;

    // grab the current cr3
    uint32_t cr3;
    asm volatile( "mov %%cr3, %0" : "=r" (cr3) );

    // setup a temporary context so that we can do the first task switch
    struct context* ctx = (struct context*) malloc( sizeof( struct context ) );
    ctx->status = PSTATE_INVALID;
    ctx->isprocess = 0;
    ctx->id = 0xffffffff;
    ctx->cr3 = cr3; // only needed for the interim where we don't have a valid task
    currprocess = ctx;
}

// cleans up
void kCleanUpScheduler()
{
	// traverse the dead queue and clean up
    /*struct pentry* ent;
	for(ent = p_deadq; ent != 0; ent = ent->next)
	{
		// unlink
		dprintf("cleaning %x [%x]\n", ent, ent->me);
		if(ent->prev)
			ent->prev->next = ent->next;
		if(ent->next)
			ent->next->prev = ent->prev;
		free(ent->me);
		free(ent);

		// this is the important bit
		p_deadq = ent->next;
	}*/
}
